package main

import (
	"crypto/md5"
	"fmt"
	"gitee.com/libbylg/pkgr/repo"
	"os"
	"path"
	"strings"
)

type CmdDownloadOptions struct {
	Filter *repo.ModuleLabelFilter
}

// NewCmdDownloadOptions
// pkgr download 	[PATTERN] [--regex] [--plan PLAN-FILE] [--env ENV-NAME]
func NewCmdDownloadOptions(argv []string) (*CmdDownloadOptions, error) {
	// 检查参数数量
	if len(argv) < 2 {
		return nil, fmt.Errorf("the required parameter is missing, try -h for help")
	}

	// 初始化默认值
	opt := &CmdDownloadOptions{
		Filter: repo.NewModuleLabelFilter(),
	}

	// 读取选项
	for index := 2; index < len(argv); index++ {
		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--regex" {
			opt.Filter.Regex = true
			continue
		}

		// 指定 plan file 场景
		if argv[index] == "--plan" {
			if len(opt.Filter.PlanFile) != 0 {
				return nil, fmt.Errorf("the install plan file has been specified with `%v'", opt.Filter.PlanFile)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanFile = argv[index]
			continue
		}

		// 指定 plan env 场景
		if argv[index] == "--view" {
			if len(opt.Filter.PlanView) != 0 {
				return nil, fmt.Errorf("the plan env has been specified with `%v'", opt.Filter.PlanView)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanView = argv[index]
			continue
		}

		if argv[index] == "--devrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "devrepo"
			continue
		}

		if argv[index] == "--pkgrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "pkgrepo"
			continue
		}

		// 遇到无法识别的选项
		if strings.HasPrefix(argv[index], "-") {
			return nil, fmt.Errorf("unsupported options `%v'", argv[index])
		}

		// 识别 PATTERN 参数
		if len(opt.Filter.Pattern) == 0 {
			opt.Filter.Pattern = argv[index]
			continue
		}

		return nil, fmt.Errorf("unsupported option `%v'", argv[index])
	}

	// 整理
	opt.Filter.Tidy("pkgrepo")

	return opt, nil
}

type DownloadResult struct {
	Error error
	HASH  string
}

func CmdDownload(argv []string) int {
	opt, err := NewCmdDownloadOptions(argv)
	if err != nil {
		ERROR("Load option for `%v' failed: %v", "download", err.Error())
		return 1
	}

	// PKGREPO 必须存在
	if !repo.PathIsDir(repo.PKGREPO) {
		ERROR("The environment variable `$PKGREPO' is missing")
		return 1
	}

	allModuleLabels, err := repo.SelectModuleLabels(opt.Filter)
	if err != nil {
		ERROR("Filter modules need to be downloaded failed: %v", err.Error())
		return 1
	}

	allFailCount := 0

	for _, label := range allModuleLabels {
		// 读取模块的 VERSION 描述文件
		descriptor, err := repo.ReadModuleVersionDescription(label.String())
		if err != nil {
			ERROR("Failed to read VERSION file for `%v': %v", label.String(), err.Error())
			return 1
		}

		// 生成模块的安装路径
		modverDir := path.Join(repo.PKGREPO, descriptor.ModuleLabel.ModuleName, descriptor.ModuleLabel.ModuleVersion)

		// 准备要一个 hash 计算器
		hash := md5.New()

		// 存储计算结果
		results := make([]DownloadResult, 0, len(descriptor.ModulePackages))
		for _, pkg := range descriptor.ModulePackages {
			// 如果无包需要下载
			if (pkg.PackageName == "-") || (pkg.PackageName == "") {
				err := fmt.Errorf("the package name is invalid: '%v'", pkg.PackageName)
				results = append(results, DownloadResult{err, ""})
				continue
			}

			// 如果没有指定下载地址
			if (pkg.DownloadURL == "-") || (pkg.DownloadURL == "") {
				err := fmt.Errorf("the download URL of the package is invalid: '%v'", pkg.PackageName)
				results = append(results, DownloadResult{err, ""})
				continue
			}

			// 开始下载包
			err := repo.DownloadFile(modverDir, pkg.PackageName, pkg.DownloadURL)
			if err != nil {
				results = append(results, DownloadResult{err, ""})
				continue
			}

			// 为下载的包计算hash值
			md5HashString, err := repo.GenFileHash(hash, path.Join(modverDir, pkg.PackageName))
			if err != nil {
				results = append(results, DownloadResult{err, ""})
				continue
			}

			// 登记下载成功结果
			results = append(results, DownloadResult{nil, md5HashString})
		}

		// 统计并展示下载结果
		failCount := 0
		for index, pkg := range descriptor.ModulePackages {
			if results[index].Error != nil {
				failCount++
				fmt.Fprintf(os.Stdout, "FAIL  %v - %v\n", pkg.PackageName, pkg.DownloadURL)
				fmt.Fprintf(os.Stdout, "      %v\n", results[index].Error.Error())
			} else {
				fmt.Fprintf(os.Stdout, "  OK  %v - %v\n", pkg.PackageName, pkg.DownloadURL)
			}
		}

		allFailCount += failCount
	}

	if allFailCount != 0 {
		return 1
	}

	return 0
}
